package middleware

import (
	"net/http"

	"github.com/casbin/casbin/v2"
)

type ctx struct{ value byte }

var (
	Subject = &ctx{0}
)

// Middleware 验证 RBAC 权限用的中间件
type Middleware struct {
	enforcer *casbin.Enforcer
}

// NewMiddleware ...
func NewMiddleware(enforcer *casbin.Enforcer) *Middleware {
	return &Middleware{
		enforcer: enforcer,
	}
}

// Operation 一次验证的 (object, action)
type Operation struct {
	Object string
	Action string
}

// Authenticate 验证中间件函数
func (mdl *Middleware) Authenticate(opt *Operation) func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			sub := r.Context().Value(Subject).(string)
			if ok, err := mdl.enforcer.Enforce(sub, opt.Object, opt.Action); err != nil || !ok {
				http.Error(w, "Authentication error", http.StatusForbidden)
				return
			}
			next.ServeHTTP(w, r)
		})
	}
}

// Authenticates 验证中间件函数(复数)
func (mdl *Middleware) Authenticates(opts []*Operation) func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			sub := r.Context().Value(Subject).(string)
			for _, opt := range opts {
				if ok, err := mdl.enforcer.Enforce(sub, opt.Object, opt.Action); err != nil || !ok {
					http.Error(w, "Authentication error", http.StatusForbidden)
					return
				}
			}
			next.ServeHTTP(w, r)
		})
	}
}
